<template>
  <div>
    <!-- 面包屑 -->
    <el-breadcrumb>
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>角色列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片区 -->
    <el-card>
      <!-- 添加角色按钮 -->
      <el-row>
        <el-col>
          <el-button type="primary" @click="showAddRoleDialog">添加角色</el-button>
        </el-col>
      </el-row>

      <!-- 添加角色对话框 -->
      <el-dialog title="添加角色" :visible.sync="setAddDialogVisible" width="50%" @close="closedAddDialog">
        <el-form :model="addForm" :rules="addRules" ref="addForm" label-width="100px" class="demo-ruleForm">
          <el-form-item label="角色名称:" prop="roleName">
            <el-input v-model="addForm.roleName"></el-input>
          </el-form-item>
          <el-form-item label="角色描述:" prop="roleDesc">
            <el-input v-model="addForm.roleDesc"></el-input>
          </el-form-item>
        </el-form>

        <!-- 底部区域 -->
        <span slot="footer" class="dialog-footer">
          <el-button @click="closedAddDialog">取 消</el-button>
          <el-button type="primary" @click="addRole">确 定</el-button>
        </span>
      </el-dialog>

      <!-- 角色列表区 -->
      <!-- 这里有一个BUG是会在发布的时候出现 原因就是element-ui支持了树形表格结构 
      只要有数据有children属性 就必须加row-key属性 否则发布的时候数据将无法渲染出来
      而且发布的时候注意cdn的版本与packjson里的版本不要冲突了
      -->

      <el-table :data="roleList" border stripe :row-key="id">
        <!-- 展开列 -->
        <el-table-column type="expand">
          <template slot-scope="scope">
            <el-row :class="['b-bottom', i1 === 0 ? 'b-top' : '', 'vcenter']" v-for="(item1, i1) in scope.row.children" :key="item1.id">
              <!-- 渲染一级权限 -->
              <el-col :span="5">
                <el-tag closable @close="removeRightById(scope.row, item1.id)">{{ item1.authName }}</el-tag>
                <i class="el-icon-caret-right"></i>
              </el-col>
              <!-- 渲染二级权限 -->
              <el-col :span="19">
                <!-- 栅格嵌套 并进行嵌套二次for循环 -->
                <el-row :class="[i2 !== 0 ? 'b-top' : '', 'vcenter']" v-for="(item2, i2) in item1.children" :key="item2.id">
                  <el-col :span="6">
                    <el-tag closable @close="removeRightById(scope.row, item2.id)">{{ item2.authName }}</el-tag>
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <el-col :span="18">
                    <!-- 第三层for循环 循环tag -->
                    <el-tag type="warning" v-for="item3 in item2.children" :key="item3.id" closable @close="removeRightById(scope.row, item3.id)">{{ item3.authName }}</el-tag>
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
        <el-table-column type="index"></el-table-column>
        <el-table-column label="角色名称" prop="roleName"></el-table-column>
        <el-table-column label="角色描述" prop="roleDesc"></el-table-column>
        <el-table-column label="操作" width="300px">
          <template slot-scope="scope">
            <el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditRoleDialog(scope.row)">编辑</el-button>
            <el-button size="mini" @click="removeRoleById(scope.row.id)" type="danger" icon="el-icon-delete">删除</el-button>
            <el-button size="mini" type="warning" icon="el-icon-setting" @click="showRightDialog(scope.row)">分配权限</el-button>
          </template>
        </el-table-column>
      </el-table>

      <!-- 修改角色对话框 -->
      <el-dialog title="修改角色" :visible.sync="setEdidDialogVisible" width="50%" @close="closedEditDialog">
        <el-form :model="editForm" :rules="editRules" ref="editForm" label-width="100px" class="demo-ruleForm">
          <el-form-item label="角色名称:" prop="roleName">
            <el-input v-model="editForm.roleName"></el-input>
          </el-form-item>
          <el-form-item label="角色描述:" prop="roleDesc">
            <el-input v-model="editForm.roleDesc"></el-input>
          </el-form-item>
        </el-form>

        <!-- 底部区域 -->
        <span slot="footer" class="dialog-footer">
          <el-button @click="closedEditDialog">取 消</el-button>
          <el-button type="primary" @click="editRoleById">确 定</el-button>
        </span>
      </el-dialog>

      <!-- 弹出分配权限对话框 -->

      <el-dialog title="分配权限" :visible.sync="setDialogVisible" width="50%" @close="closedRightDialog">
        <!-- 树形权限展示 -->
        <el-tree
          :data="rightTree"
          :props="rightProps"
          node-key="id"
          show-checkbox
          default-expand-all
          :default-expanded-keys="defaultExpandedKeys"
          :default-checked-keys="defaultExpandedKeys"
          ref="refTree"
        ></el-tree>
        <span slot="footer" class="dialog-footer">
          <el-button @click="closedRightDialog">取 消</el-button>
          <el-button type="primary" @click="allotRight">确 定</el-button>
        </span>
      </el-dialog>
    </el-card>
  </div>
</template>

<script>
export default {
  created() {
    this.getRolesList()
  },
  data() {
    return {
      roleList: [],
      //设置弹出分配权限对话框可见
      setDialogVisible: false,
      rightTree: [],
      rightProps: {
        label: 'authName',
        children: 'children',
      },
      //设置默认树形列表展开的节点
      defaultExpandedKeys: [],

      //即将分配权限的角色id
      roleId: '',
      //分配成功保留当前行展开的字段
      //rightRow: '',
      //控制修改角色对话框的显示与隐藏
      setEdidDialogVisible: false,
      editRules: {
        roleName: [
          { required: true, message: '请输入角色名', trigger: 'blur' },
          { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' },
        ],
        roleDesc: [
          { required: false, message: '请输入角色描述', trigger: 'blur' },
          {
            min: 0,
            max: 10,
            message: '长度在 0 到 10 个字符',
            trigger: 'blur',
          },
        ],
      },
      editForm: {
        roleName: '',
        roleDesc: '',
        id: '',
      },
      addForm: {
        roleName: '',
        roleDesc: '',
      },

      addRules: {
        roleName: [
          { required: true, message: '请输入角色名', trigger: 'blur' },
          { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' },
        ],
        roleDesc: [
          { required: false, message: '请输入角色描述', trigger: 'blur' },
          {
            min: 0,
            max: 10,
            message: '长度在 0 到 10 个字符',
            trigger: 'blur',
          },
        ],
      },
      setAddDialogVisible: false,
    }
  },

  methods: {
    async getRolesList() {
      const { data: res } = await this.$http.get('roles')

      if (res.meta.status !== 200) {
        return this.$message.error('获取角色列表失败')
      }

      //获取成功 就将数据给roleList
      this.roleList = res.data
      //console.log(this.roleList)
    },
    //获取所有的权限树形列表
    async getRightsList() {
      const { data: res } = await this.$http.get('rights/tree')

      if (res.meta.status !== 200) {
        return this.$message.error('获取权限列表失败')
      }

      this.rightTree = res.data

      //console.log(res.data)
      //console.log(res.data[0].children.length)

      //获取权限列表三级权限中的id
      //作为默认展开项
      //if (
      //res.data[0].children.length &&
      //res.data[0].children[0].children.length
      //) {
      //let defaultExpandedKeys = []
      //console.log(defaultExpandedKeys)
      //res.data[0].children[0].children.forEach((item) => {
      //console.log(item.id)
      //defaultExpandedKeys.push(item.id)
      //})

      //this.defaultExpandedKeys = defaultExpandedKeys
      //}

      //console.log(this.defaultExpandedKeys)
    },
    //获取权限列表三级权限中的id
    getDefaultKeys(node, arr) {
      //console.log(node)
      //没有children就是三级权限（最底层权限）
      //当一个角色没有权限时 它的children是一个空数组
      //我们去获取一个数组中没有的属性 默认返回值是undefined
      //但是在vue 返回的是Observer观察者对象
      if (!node.children) {
        //返回默认展开当前id的权限列表
        //console.log(node.children)
        //console.log(node.id)
        return arr.push(node.id)
      }
      //有children属性 不是三级权限 还要进行递归判断
      node.children.forEach((item) => {
        this.getDefaultKeys(item, arr)
      })
    },

    //展示所有权限的数据 以树形方式
    showRightDialog(right) {
      //将当前的角色id传递出去 方便后面为当前角色分配权限
      this.roleId = right.id
      //弹出对话框时获取权限列表
      this.getRightsList()
      //获取当前权限默认展开项id
      this.getDefaultKeys(right, this.defaultExpandedKeys)

      //console.log(this.defaultExpandedKeys)
      this.setDialogVisible = !this.setDialogVisible
    },
    //关闭权限列表对话框 初始化默认状态
    closedRightDialog() {
      this.defaultExpandedKeys = []
      this.setDialogVisible = false
    },

    //为角色分配权限 需要获取半展开、选中节点的id值
    async allotRight() {
      const keys = [...this.$refs.refTree.getCheckedKeys(), ...this.$refs.refTree.getHalfCheckedKeys()]

      const idStr = keys.join(',')
      console.log(idStr)

      const { data: res } = await this.$http.post(`roles/${this.roleId}/rights`, {
        rids: idStr,
      })

      if (res.meta.status !== 200) {
        return this.$message.error('分配权限失败')
      }

      this.$message.success('权限分配成功')
      //权限分配成功刷新权限列表 会关闭掉当前的展开行
      this.getRolesList()
      //row.children = res.data
      this.setDialogVisible = !this.setDialogVisible
    },

    //saveCurrentExpand(row) {
    //this.rightRow = row
    //row.children =
    //console.log(this.roleList.data)
    //},
    //删除角色
    async removeRoleById(roleId) {
      const confirm = await this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).catch((err) => err)

      console.log(confirm)

      if (confirm !== 'confirm') {
        return this.$message.info('取消删除')
      }

      const { data: res } = await this.$http.delete(`roles/${roleId}`)

      if (res.meta.status !== 200) {
        return this.$message.error('删除角色失败')
      }

      this.$message.success('删除角色成功')
      this.getRolesList()
    },

    //弹出修改角色对话框
    showEditRoleDialog(row) {
      //传递要用到的属性
      this.editForm.roleName = row.roleName
      this.editForm.roleDesc = row.roleDesc
      this.editForm.id = row.id

      this.setEdidDialogVisible = true
    },

    //修改角色
    editRoleById(id) {
      id = this.editForm.id
      //修改角色前预验证下数据
      this.$refs.editForm.validate(async (valid) => {
        if (!valid) {
          return this.$message.error('请检查数据是否填写正确')
        }
        const { data: res } = await this.$http.put(
          `roles/${id}`,
          {
            roleName: this.editForm.roleName,
          },
          {
            roleDesc: this.editForm.roleDesc,
          }
        )

        if (res.meta.status !== 200) {
          return this.$message.error('修改角色失败')
        }

        this.$message.success('修改角色成功')
        this.getRolesList()
        this.setEdidDialogVisible = false
      })
    },
    //关闭修改角色对话框
    closedEditDialog() {
      this.$refs.editForm.resetFields()
      this.setEdidDialogVisible = false
    },
    //弹出添加角色对话框
    showAddRoleDialog() {
      this.setAddDialogVisible = true
    },
    //添加角色
    addRole() {
      this.$refs.addForm.validate(async (valid) => {
        if (!valid) return this.$message.error('请检查数据是否填写正确')
        //console.log(this.addForm.roleDesc)
        //预验证通过后再发请求
        const { data: res } = await this.$http.post('roles', {
          roleName: this.addForm.roleName,
          roleDesc: this.addForm.roleDesc,
        })

        if (res.meta.status !== 201) {
          return this.$message.error('添加角色失败')
        }

        this.$message.success('添加角色成功')

        this.getRolesList()
      })
      this.setAddDialogVisible = false
    },
    //关闭添加角色对话框
    closedAddDialog() {
      this.$refs.addForm.resetFields()
      this.setAddDialogVisible = false
    },

    //删除权限
    async removeRightById(row, rightId) {
      //为分配权限成功时能够刷新当前展开行
      this.rightRow = row

      const confirm = await this.$confirm('此操作将永久删除该权限, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).catch((err) => err)

      console.log(confirm)

      if (confirm !== 'confirm') {
        return this.$message.info('取消删除')
      }

      const { data: res } = await this.$http.delete(`roles/${row.id}/rights/${rightId}`)

      if (res.meta.status !== 200) {
        this.$message.error('删除权限失败')
      }

      this.$message.success('删除权限成功')
      //删除成功更新数据 但不要去调用this.getRolesList() 会刷新整个页面
      //进行渲染 从而把当前打开的选项卡给关闭

      //直接用服务器返回的数据给 当前函数形参传递进来的scope.row中的children
      //这样可以很方便使用作用域插槽进行不更新整个页面进行渲染 而是当前数据局部进行渲染
      row.children = res.data
    },
  },
}
</script>

<style lang="less" scoped>
.el-tag {
  margin: 7px;
  //text-align: center;
}

.b-top {
  border-top: 1px solid #333;
}

.b-bottom {
  border-bottom: 1px solid #333;
}

.vcenter {
  display: flex;
  align-items: center;
}

.roleNameInput {
  width: 80% !important;
}
</style>
